import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author wcj
 * @Date 2021/6/8 20:02
 * @Version 1.0
 */
public class DefaultThreadPool<Job extends Runnable> implements ThreadPool<Job> {

 /**
  * 线程池的最大限制数
  */
 private static final int MAX_WORKER_NUMBER = 10;

 /**
  * 线程池的默认限制数
  */
 private static final int DEFAULT_WORKER_NUMBER = 5;

 /**
  * 线程池的最小限制数
  */
 private static final int MIN_WORKER_NUMBER = 1;

 /**
  * 工作列表：用于服务端向其中添加工作
  */
 private final LinkedList<Job> jobs = new LinkedList<>();

 /**
  * 工作者列表：存储用于读取工作的工作者
  */
 private final List<Worker> workers = Collections.synchronizedList(new ArrayList<Worker>());

 /**
  * 工作者线程的数量
  */
 private int workerNum = DEFAULT_WORKER_NUMBER;

 /**
  * 线程编号
  */
 private AtomicInteger threadNum = new AtomicInteger();

 public DefaultThreadPool() {
  initializeWorkers(DEFAULT_WORKER_NUMBER);
 }

 public DefaultThreadPool(int num) {
  workerNum = num > MAX_WORKER_NUMBER ? MAX_WORKER_NUMBER : num < MIN_WORKER_NUMBER ? MIN_WORKER_NUMBER : num;
  initializeWorkers(workerNum);
 }


 @Override
 public void execute(Job job) {
  if (job != null) {
   synchronized (jobs) {
    jobs.addLast(job);
    jobs.notify();
   }
  }
 }

 @Override
 public void shutDown() {
  for (Worker worker : workers) {
   worker.shutDown();
  }
 }

 @Override
 public void addWorkers(int num) {
  synchronized (jobs) {
   if (num + this.workerNum > MAX_WORKER_NUMBER) {
    num = MAX_WORKER_NUMBER - this.workerNum;
   }
   initializeWorkers(num);
   this.workerNum += num;
  }
 }

 @Override
 public void removeWorkers(int num) {
  synchronized (jobs) {
   if (num >= this.workerNum) {
    throw new IllegalArgumentException("beyond workNum");
   }
   int count = 0;
   while (count < num) {
    Worker worker = workers.get(count);
    if (workers.remove(worker)) {
     worker.shutDown();
     count++;
    }
   }
   this.workerNum -= count;
  }
 }

 @Override
 public int getJogSize() {
  return jobs.size();
 }

 public void initializeWorkers(int num) {
  for (int i = 0; i < num; i++) {
   Worker worker = new Worker();
   workers.add(worker);
   Thread thread = new Thread(worker, "ThreadPool-Worker-" + threadNum.incrementAndGet());
   thread.start();
  }
 }

 class Worker implements Runnable {
  private volatile boolean running = true;

  @Override
  public void run() {
   while (running) {
    Job job = null;
    synchronized (jobs) {
     while (jobs.isEmpty()) {
      try {
       jobs.wait();
      } catch (InterruptedException e) {
       e.printStackTrace();
      }
     }
     job = jobs.removeFirst();
    }
    if (job != null) {
     job.run();
    }
   }
  }

  public void shutDown() {
   running = false;
  }
 }
}
